package ar.edu.utn.frsf.tpae.a2014.g02.persistence.dao.impl;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ar.edu.utn.frsf.tpae.a2014.g02.persistence.dao.PedidoDao;
import ar.edu.utn.frsf.tpae.a2014.g02.persistence.model.Cliente;
import ar.edu.utn.frsf.tpae.a2014.g02.persistence.model.EstadoPedido;
import ar.edu.utn.frsf.tpae.a2014.g02.persistence.model.HistorialPedido;
import ar.edu.utn.frsf.tpae.a2014.g02.persistence.model.Pedido;
import ar.edu.utn.frsf.tpae.a2014.g02.persistence.model.Transportista;

/**
 * DAO de Pedido basado en Hibernate.
 * 
 * @author TPAE
 */
@Component
public class PedidoHibernateDao implements PedidoDao {

	private SessionFactory sessionFactory;

	// Setter utilizado por Spring.
	@Autowired(required = true)
	public void setSessionFactory(SessionFactory factory) {
		this.sessionFactory = factory;
	}

	private Session getCurrentSession() {
		return sessionFactory.getCurrentSession();
	}

	@SuppressWarnings("unchecked")
	public List<Pedido> listar() {
		Session session = getCurrentSession();
		Query query = session.createQuery("from Pedido ");
		return query.list();
	}

	public List<Pedido> listarSegunClienteEstado(Cliente cliente,
			EstadoPedido estadoPedido) {
		Query query = getCurrentSession().createQuery(
				getConsultaPedidosSegunClienteYEstado());
		query.setParameter("estado", estadoPedido);
		query.setParameter("idCliente", cliente.getId());

		return (List<Pedido>) query.list();
	}

	public List<Pedido> listarSegunEstado(EstadoPedido estadoPedido) {
		Query query = getCurrentSession().createQuery(
				getConsultaPedidosSegunEstado());
		query.setParameter("estado", estadoPedido.getEstado());

		return (List<Pedido>) query.list();
	}

	private String getConsultaPedidosSegunEstado() {
		return "SELECT pedido "
				+ "FROM Pedido pedido, HistorialPedido hist "
				+ "WHERE hist.pedido.id = pedido.id "
				+ " and hist.id="
				+ "(SELECT max(histPedido.id) "
				+ "FROM HistorialPedido histPedido "
				+ "WHERE histPedido.pedido.id = pedido.id) and hist.estado = :estado";
	}

	private String getConsultaPedidosSegunClienteYEstado() {
		return "SELECT pedido "
				+ "FROM Pedido pedido, HistorialPedido hist "
				+ "WHERE hist.pedido.id = pedido.id "
				+ " and pedido.cliente.id = :idCliente and hist.id="
				+ "(SELECT max(histPedido.id) "
				+ "FROM HistorialPedido histPedido "
				+ "WHERE histPedido.pedido.id = pedido.id) and hist.estado = :estado";
	}

	private String getConsultaPedidosInEstados() {
		return "SELECT pedido "
				+ "FROM Pedido pedido, HistorialPedido hist "
				+ "WHERE hist.pedido.id = pedido.id "
				+ " and hist.id="
				+ "(SELECT max(histPedido.id) "
				+ "FROM HistorialPedido histPedido "
				+ "WHERE histPedido.pedido.id = pedido.id) and hist.estado in (:estado)";
	}

	public List<Pedido> listarPedidosSinAsignar() {
		Query query = getCurrentSession().createQuery(
				getConsultaPedidosSegunEstado());
		query.setParameter("estado", EstadoPedido.ACEPTADO);

		return (List<Pedido>) query.list();
	}

	public List<Pedido> listarOrdenesAsignadas(Transportista transportista) {
		Query query = getCurrentSession().createQuery(
				getConsultaPedidosInEstados()
						+ " and pedido.transportirsta.id = :idTransportista");
		query.setParameter("idTransportista", transportista.getId());
		List<EstadoPedido> estados = new ArrayList<EstadoPedido>();
		estados.add(EstadoPedido.A_RETIRAR);
		estados.add(EstadoPedido.EN_TRANSPORTE);
		query.setParameterList("estado", estados);

		return (List<Pedido>) query.list();
	}

	public Pedido persistir(Pedido pedido) {
		Session session = getCurrentSession();
		session.saveOrUpdate(pedido);
		return pedido;
	}

	public void deleteAll() {
		Session session = getCurrentSession();
		Query query = session.createQuery("delete from "
				+ HistorialPedido.class.getName());
		query.executeUpdate();
		Query query2 = session.createQuery("delete from "
				+ Pedido.class.getName());
		query2.executeUpdate();
	}

	@SuppressWarnings("unchecked")
	@Override
	public EstadoPedido getEstadoPedidoById(Integer idPedido) {
		Query query = getCurrentSession().createQuery(
				"from HistorialPedido as historial "
						+ " where historial.pedido.id = :idPedido"
						+ " order by historial.fechaHoraRegistroCambio DESC");
		query.setParameter("idPedido", idPedido);
		List<HistorialPedido> historial = (List<HistorialPedido>) query.list();
		return historial.get(0).getEstado();
	}

	@Override
	public List<Pedido> listarPedidosSegunClienteId(Integer idCliente) {
		return (List<Pedido>) getCurrentSession()
				.createQuery(
						"from Pedido pedido where pedido.cliente.id = :idCliente ")
				.setParameter("idCliente", idCliente).list();
	}

	@Override
	public Pedido getPedidoById(Integer id) {
		return (Pedido) getCurrentSession()
		.createQuery(
				"from Pedido pedido where pedido.id = :idPedido ")
		.setParameter("idPedido", id).uniqueResult() ;
	}
}
